/**
 * Copyright (c) 2015-2017, Henry Yang 杨勇 (gismail@foxmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lambkit.module.upms.server;

import com.google.common.collect.Maps;
import com.jfinal.core.Controller;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.lambkit.Lambkit;
import com.lambkit.module.upms.server.service.*;
import com.lambkit.module.upms.server.service.impl.UpmsUserModelServiceImpl;
import com.lambkit.web.LambkitResult;
import com.lambkit.common.util.DateTimeUtils;
import com.lambkit.common.util.EncryptUtils;

import com.lambkit.db.sql.column.Example;
import com.lambkit.module.upms.common.LoginService;
import com.lambkit.module.upms.common.UpmsResult;
import com.lambkit.module.upms.common.UpmsResultConstant;
import com.lambkit.module.upms.common.Validator;
import com.lambkit.module.upms.model.UpmsLogModel;
import com.lambkit.module.upms.model.UpmsPermissionModel;
import com.lambkit.module.upms.model.UpmsSystemModel;
import com.lambkit.module.upms.model.UpmsUserModel;
import com.lambkit.module.upms.model.UpmsUserOrganizationModel;
import com.lambkit.module.upms.model.UpmsUserRoleModel;
import com.lambkit.plugin.sms.SmsManager;
import com.lambkit.plugin.auth.AuthManager;
import com.lambkit.plugin.mail.MailKit;
import com.lambkit.plugin.mail.exception.MailSendException;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.lambkit.common.util.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

public class UpmsEmbeddedLoginService implements LoginService {

	// 密码过期时间，90天
	private static final Long PASSWORD_MAX = 7776000000L;

	public void captcha(Controller controller) {
		controller.renderCaptcha();
	}

	public void sms(Controller controller) {
		String mobile = controller.getPara(0);
		if (StrKit.isBlank(mobile)) {
			LambkitResult result = new UpmsResult(UpmsResultConstant.FAILED, "手机号不能为空", mobile);
			controller.renderJson(result);
			return;
		}

		UpmsUserModel upmsUser = UpmsServerManager.me().getUpmsApiService().selectUpmsUserByPhone(mobile);
		if (null == upmsUser) {
			Subject subject = SecurityUtils.getSubject();
			Session session = subject.getSession();
			Integer error = addLoginError(session);
			LambkitResult result = new UpmsResult(UpmsResultConstant.INVALID_USERNAME,
					"帐号不存在！错误" + error + "次，错误6次后锁定");
			controller.renderJson(result);
			return;
		}
		if (Validator.isMobile(mobile)) {
			int flag = SmsManager.me().sendVerifyLoginSMS(mobile);
			if (flag == 200) {
				LambkitResult result = new UpmsResult(UpmsResultConstant.SUCCESS, "newCode", mobile);
				controller.renderJson(result);
				return;
			} else if (flag == 10501) {
				LambkitResult result = new UpmsResult(UpmsResultConstant.SUCCESS, "oldCode", mobile);
				controller.renderJson(result);
				return;
			}
		}
		LambkitResult result = new UpmsResult(UpmsResultConstant.FAILED, "验证码发送失败", mobile);
		controller.renderJson(result);
	}

	private Integer addLoginError(Session session) {
		Object error = session.getAttribute("login_error");
		if (error != null) {
			Integer ier = (Integer) error;
			ier++;
			session.setAttribute("login_error", ier);
			return ier;
		} else {
			session.setAttribute("login_error", Integer.valueOf(1));
			return 1;
		}
	}

	public void login(Controller controller) {
		if (controller.getRequest().getMethod().equals("GET")) {
			Subject subject = SecurityUtils.getSubject();
			Session session = subject.getSession();
			String serverSessionId = session.getId().toString();
			// 判断是否已登录，如果已登录，则回跳
			String code = UpmsServerManager.me().getCache().getSession(serverSessionId);
			String username = (String) subject.getPrincipal();
			// code校验值
			if (StringUtils.isNotBlank(code) && StrKit.notBlank(username) && !username.equals("null")) {
				// 回跳
				String backurl = controller.getRequest().getParameter("backurl");
				// String username = (String) subject.getPrincipal();
				if (StringUtils.isBlank(backurl)) {
					backurl = "/";
					backurl = subject.hasRole("admin") ? "/manage" : "";
					backurl = subject.hasRole("super") ? "/manage" : "";
				} else {
					if (backurl.contains("?")) {
						backurl += "&upms_code=" + code + "&upms_username=" + username;
					} else {
						backurl += "?upms_code=" + code + "&upms_username=" + username;
					}
				}
				if(Lambkit.isDevMode()) {
					System.out.println("认证中心帐号通过，带code回跳：{}" + backurl);
				}
				if (backurl.startsWith("/")) {
					backurl = backurl.substring(1);
				}
				controller.redirect(backurl);
			} else {
				controller.keepPara();
				// renderJsp("login.jsp");
				controller.renderTemplate("login.html");
			}
		} else {
			controller.renderJson(AuthManager.me().getService().login(controller));
		}
	}
	
	@Override
	public void unPasswordLogin(Controller controller) {
		String userName = controller.get("username", null);
		AuthManager.me().getService().login(controller.getRequest(), userName);
		Session session = SecurityUtils.getSubject().getSession();
		controller.renderJson(new UpmsResult(UpmsResultConstant.SUCCESS, session.getId()));
	}

	public void logout(Controller controller) {
		LambkitResult result = AuthManager.me().getService().logout(controller.getRequest());
		String redirectUrl = String.valueOf(result.getData());
		if (null == redirectUrl) {
			redirectUrl = "/";
		}
		if (redirectUrl.startsWith("/"))
			redirectUrl = redirectUrl.substring(1);
		controller.redirect(redirectUrl);
	}

	public void ajaxLogout(Controller controller) {
		AuthManager.me().getService().logout(controller.getRequest());
		controller.renderJson(new UpmsResult(UpmsResultConstant.SUCCESS, "logout"));
	}

	@Override
	public void authenticate(Controller controller) {
		// TODO Auto-generated method stub
		String appid = controller.getPara("appid");
		String serverSessionId = controller.getPara("sessionid");
		if (StringUtils.isBlank(appid) || StringUtils.isBlank(serverSessionId)) {
			// System.out.println("无效访问appid is null");
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "无效访问"));
			return;
		}
		// 判断请求认证系统是否注册
		Example upmsSystemExample = UpmsSystemModel.sql().andNameEqualTo(appid).example();
		Long count = UpmsSystemModel.service().count(upmsSystemExample);
		if (count != null && 0 == count) {
			// System.out.println(String.format("未注册的系统:%s", appid));
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, String.format("未注册的系统:%s", appid)));
			return;
		}
		// 判断是否已登录，如果已登录，则回跳
		String code = UpmsServerManager.me().getCache().getSession(serverSessionId);
		// code校验值
		if (StringUtils.isNotBlank(code) && code.startsWith(serverSessionId + "&")) {
			// String username = code.substring(code.lastIndexOf("&"));
			String username = code.replace(serverSessionId + "&", "");
			if(Lambkit.isDevMode()) {
				System.out.println("authenticate: " + username);
			}
			// UpmsApiService upmsApiService = Lambkit.get(UpmsApiServiceImpl.class);
			// UpmsUserModel user = upmsApiService.selectUpmsUserByLoginName(username);
			// user.removeSensitiveInfo();
			LambkitResult result = new UpmsResult(UpmsResultConstant.SUCCESS, username, code);
			UpmsLogModel.service().addLog(username, "用户校验", "authenticate", result, "authenticate", controller.getRequest());
			controller.renderJson(result);
		} else {
			// System.out.println("无效访问unlogin");
			LambkitResult result = new UpmsResult(UpmsResultConstant.FAILED, "unlogin");
			UpmsLogModel.service().addLog(appid, "用户校验", "authenticate", result, "authenticate", controller.getRequest());
			controller.renderJson(result);
		}
	}

	@Override
	public void userinfo(Controller controller) {
		// TODO Auto-generated method stub
		UpmsUserModel user = controller.getAttr("upmsUser");
		if (user == null) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "账号错误！"));
			return;
		}
		user.removeSensitiveInfo();
		Kv data = Kv.by("user", user);

		// 用户拥有组织
		Example upmsUserOrganizationExample = UpmsUserOrganizationModel.sql().andUserIdEqualTo(user.getUserId())
				.example();
		List<UpmsUserOrganizationModel> upmsUserOrganizations = UpmsUserOrganizationModel.service()
				.find(upmsUserOrganizationExample);
		data.set("userOrganizations", upmsUserOrganizations);

		// 用户拥有角色
		Example upmsUserRoleExample = UpmsUserRoleModel.sql().andUserIdEqualTo(user.getUserId()).example();
		List<UpmsUserRoleModel> upmsUserRoles = UpmsUserRoleModel.service().find(upmsUserRoleExample);
		data.set("userRoles", upmsUserRoles);
		// 用户权限
		List<UpmsPermissionModel> permissions = UpmsServerManager.me().getUpmsApiService()
				.selectUpmsPermissionByUpmsUserId(user.getUserId());
		data.set("userPermissions", permissions);
		// 密码超期提醒
		Date pwLastTime = user.getPwLastTime();
		Long time = new Date().getTime() - pwLastTime.getTime();
		if (PASSWORD_MAX - time > 0) {
			data.set("passwordOverdue", 0);// 90天未修改密码
		} else {
			data.set("passwordOverdue", 1);
		}
		controller.renderJson(new UpmsResult(UpmsResultConstant.SUCCESS, user.getUsername(), data));
	}

	@Override
	public void regist(Controller controller) {
		// TODO Auto-generated method stub
		controller.renderJson(doRegist(controller));
	}

	private UpmsResult doRegist(Controller controller) {
		final String username = controller.getRequest().getParameter("username");
		final String password = controller.getRequest().getParameter("password");
		String repswd = controller.getRequest().getParameter("repswd");
		String captcha = controller.getRequest().getParameter("captcha");
		if (StringUtils.isBlank(username)) {
			return new UpmsResult(UpmsResultConstant.EMPTY_USERNAME, "帐号不能为空！");
		}
		if (StringUtils.isBlank(password)) {
			return new UpmsResult(UpmsResultConstant.EMPTY_PASSWORD, "密码不能为空！");
		}
		if (StringUtils.isBlank(repswd)) {
			return new UpmsResult(UpmsResultConstant.EMPTY_REPSWD, "确认密码不能为空！");
		}
		if (!password.equals(repswd)) {
			return new UpmsResult(UpmsResultConstant.INVALID_PASSWORD, "密码不一致！");
		}
		if (StringUtils.isBlank(captcha)) {
			return new UpmsResult(UpmsResultConstant.EMPTY_CAPTCHA, "验证码不能为空！");
		}
		if (!controller.validateCaptcha("captcha")) {
			// 判断请求认证系统是否注册
			Example upmsSystemExample = UpmsSystemModel.sql().andNameEqualTo(captcha).example();
			Long count = UpmsSystemModel.service().count(upmsSystemExample);
			if (count == null || 0 == count) {
				return new UpmsResult(UpmsResultConstant.INVALID_CAPTCHA, "验证码不正确！");
			}
		}

		boolean flag = Db.tx(new IAtom() {

			public boolean run() throws SQLException {
				// TODO Auto-generated method stub
				UpmsUserModelService upmsUserService = Lambkit.get(UpmsUserModelServiceImpl.class);
				UpmsUserModel upmsUser = controller.getModel(UpmsUserModel.class, "user");
				upmsUser.setUsername(username);
				upmsUser.setSalt(StrKit.getRandomUUID());
				String md5pswd = EncryptUtils.MD5(password + upmsUser.getSalt());
				upmsUser.setPassword(md5pswd);
				String realname = controller.getPara("realname");
				if (StringUtils.isNotBlank(realname)) {
					upmsUser.setRealname(realname);
				}
				String email = controller.getPara("email");
				if (StringUtils.isNotBlank(email)) {
					upmsUser.setEmail(email);
				}
				String phone = controller.getPara("phone");
				if (StringUtils.isNotBlank(phone)) {
					upmsUser.setPhone(phone);
				}
				upmsUser.setLocked(controller.getParaToInt("locked", 0));
				upmsUser.setSex(controller.getParaToInt("sex", 1));
				upmsUser.setCtime(DateTimeUtils.getCurrentTimeLong());
				upmsUser.setAvatar(controller.getPara("avatar", "/lambkit/assets/upms/images/avatar.jpg"));
				UpmsUserModel user = upmsUserService.createUser(upmsUser);
				if (user == null) {
					return false;
				}
				UpmsUserRoleModel upmsUserRole = new UpmsUserRoleModel();
				upmsUserRole.setUserId(upmsUser.getUserId());
				upmsUserRole.setRoleId(3L);
				boolean rflag = upmsUserRole.save();
				return rflag;
			}
		});
		if (!flag) {
			return new UpmsResult(UpmsResultConstant.FAILED, "注册失败！");
		}
		// 回跳登录前地址
		String backurl = controller.getRequest().getParameter("backurl");
		UpmsResult result = new UpmsResult(UpmsResultConstant.SUCCESS, backurl);
		if (StringUtils.isBlank(backurl)) {
			if ("admin".equals(username)) {
				result = new UpmsResult(UpmsResultConstant.SUCCESS, "/lambkit/upms");
			} else {
				result = new UpmsResult(UpmsResultConstant.SUCCESS, "/");
			}
		}
		UpmsLogModel.service().addRegistLog(username, result, controller.getRequest());
		return result;
	}

	@Override
	public void repswd(Controller controller) {
		// 原密码
		String ypass = controller.getPara("ypass");
		String xpass = controller.getPara("password");
		String qrxpass = controller.getPara("qrxpass");

		// 当前登录用户权限
		Subject subject = SecurityUtils.getSubject();
		String username = (String) subject.getPrincipal();

		UpmsServerApiService upmsApiService = UpmsServerManager.me().getUpmsApiService();
		UpmsUserModel upmsUser = upmsApiService.selectUpmsUserByUsername(username);
		if (upmsUser == null) {
			// shiro退出登录
			SecurityUtils.getSubject().logout();
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "未登录"));
			return;
		}
		String ymd5pswd = EncryptUtils.MD5(ypass + upmsUser.getSalt());
		String xmd5pswd = EncryptUtils.MD5(xpass + upmsUser.getSalt());
		if (ypass.equals("") || xpass.equals("") || qrxpass.equals("")) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "请填写完整信息"));
			return;
		} else if (!ymd5pswd.equals(upmsUser.getPassword())) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "原密码错误"));
			return;
		} else if (xmd5pswd.equals(upmsUser.getPassword())) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "新密码不能和原密码一样"));
			return;
		} else if (!xpass.equals(qrxpass)) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "新密码必须和确认新密码一样"));
			return;
		} else if (xpass.length() < 6 || xpass.length() > 12) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "新密码的长度为6-12位"));
			return;
		}
		upmsUser.setPassword(xmd5pswd);
		boolean flag = upmsUser.update();
		if (flag)
			controller.renderJson(new UpmsResult(UpmsResultConstant.SUCCESS, "更新成功"));
		else
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "更新失败"));
	}

	@Override
	public void forgot(Controller controller) {
		// TODO Auto-generated method stub
		String LoginName = controller.getPara(0, controller.getPara("name"));
		String email = controller.getPara(1, controller.getPara("email"));
		if (StringUtils.isBlank(LoginName)) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.EMPTY_USERNAME, "帐号不能为空！"));
			return;
		}
		if (StringUtils.isBlank(email)) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.EMPTY_CAPTCHA, "邮箱不能为空！"));
			return;
		}
		UpmsServerApiService upmsApiService = UpmsServerManager.me().getUpmsApiService();
		UpmsUserModel user = upmsApiService.selectUpmsUserByLoginName(LoginName);
		if (user == null) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.INVALID_USERNAME, "帐号不存在！"));
			return;
		}
		if (StringUtils.isBlank(user.getEmail())) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "未绑定邮箱！"));
			return;
		} else if (!email.equals(user.getEmail())) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.INVALID_CAPTCHA, "邮箱不正确！"));
			return;
		}
		String token = com.lambkit.common.util.StringUtils.uuid();
		UpmsServerManager.me().getCache().set(user.getUsername() + "-emailpswd-token", token, 180);
		Map<String, Object> dataMap = Maps.newHashMap();
		dataMap.put("token", token);
		dataMap.put("username", user.getUsername());
		dataMap.put("email", user.getEmail());
		dataMap.put("user", user);
		try {
			MailKit.send(user.getEmail(), null, "注册账号密码重置邮件", "email/pswd.html", dataMap);
		} catch (MailSendException e) {
			e.printStackTrace();
			LambkitResult result = new UpmsResult(UpmsResultConstant.FAILED, "邮件发送失败！");
			UpmsLogModel.service().addLog(user.getUsername(), "忘记密码", "forgot", result, "forgot", controller.getRequest());
			controller.renderJson(result);
			return;
		}
		LambkitResult result = new UpmsResult(UpmsResultConstant.SUCCESS, "邮件已发送！");
		UpmsLogModel.service().addLog(user.getUsername(), "忘记密码", "forgot", result, "forgot", controller.getRequest());
		controller.renderJson(result);
	}

	@Override
	public void reset(Controller controller) {
		// TODO Auto-generated method stub
		String name = controller.getPara("name");
		String token = controller.getPara("token");
		String pswd = controller.getPara("pswd");
		String repswd = controller.getPara("repswd");
		if (pswd.equals("") || repswd.equals("")) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "请填写完整信息"));
			return;
		} else if (!pswd.equals(repswd)) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "新密码必须和确认新密码一样"));
			return;
		} else if (pswd.length() < 6 || pswd.length() > 12) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.FAILED, "新密码的长度为6-12位"));
			return;
		}
		if (StringUtils.isBlank(name)) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.EMPTY_USERNAME, "帐号不能为空！"));
			return;
		}
		if (StringUtils.isBlank(token)) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.EMPTY_CAPTCHA, "链接已过期！"));
			return;
		}
		UpmsServerApiService upmsApiService = UpmsServerManager.me().getUpmsApiService();
		UpmsUserModel upmsUser = upmsApiService.selectUpmsUserByUsername(name);
		if (upmsUser == null) {
			controller.renderJson(new UpmsResult(UpmsResultConstant.INVALID_USERNAME, "帐号不存在！"));
		} else {
			String localToken = UpmsServerManager.me().getCache().get(upmsUser.getUsername() + "-emailpswd-token");
			if(Lambkit.isDevMode()) {
				System.out.println(localToken);
			}
			if (!token.equals(localToken)) {
				controller.renderJson(new UpmsResult(UpmsResultConstant.INVALID_CAPTCHA, "链接已过期！"));
				return;
			}
			String md5pswd = EncryptUtils.MD5(pswd + upmsUser.getSalt());
			upmsUser.setPassword(md5pswd);
			Boolean flag = upmsUser.update();
			LambkitResult result = new UpmsResult(UpmsResultConstant.FAILED, "更新失败");
			if (flag) {
				result = new UpmsResult(UpmsResultConstant.SUCCESS, "更新成功");
			}
			UpmsLogModel.service().addLog(upmsUser.getUsername(), "修改密码", "reset", result, "reset", controller.getRequest());
			controller.renderJson(result);
		}
	}
}
